﻿#pragma once

#include<iostream>
#include <filesystem>
#include <fstream>
#include <stdint.h>
#include <memory>
#include <unordered_map>
#include <vector>
#include <base_type/bar_type.h>
#include <cppbase/bitset_type.h>
#include <cppbase/datetime_type.h>
#include<list>
#include<map>
#include<set>
#include <string_view>
#include "file_base.h"

//bitmap,startdate(4),lastdate(4),rowsize(2),footsize(2)
#pragma pack(push, 2)
struct BarFileFoot {
	uint32_t firstdate;
	uint32_t lastdate;
	uint16_t rowsize;
	int16_t footsize;
};
#pragma pack(pop)

class TdxFileStore;
class MyFileStore :public FileStoreBase {
	TdxFileStore* tdx=nullptr;
	static MyFileStore* inst;
	std::string trading_date_fn = "trading_date.txt";
	//inline bool test_bit_set(uint8_t* bitmap, int bitmap_len,int index);
	//inline int count_bit(uint8_t* bitmap, int index);
	//void set_bit(char* bit, int cnt);
	std::list<uint32_t> read_trading_date();
	std::unordered_map<uint32_t, int32_t> local_trading_date(std::string symbol = "-");
	virtual uint16_t row_size(BarSize barsize) override;
	virtual std::filesystem::path get_filepath(Exchange exchangeid, std::string symbol, BarSize barsize) override;
	
	//根据date list，获得bit map
	dynamic_bitset<> get_bitmap(std::map<uint32_t, std::vector<MinuteBar>>* bars);
	dynamic_bitset<> get_bitmap(std::set<Bar> bars);
	dynamic_bitset<> get_bitmap(std::map<uint32_t,Bar>* bars);
	dynamic_bitset<> get_bitmap(std::vector<Bar>* bars);
	dynamic_bitset<> get_bitmap(Bar* buf,int cnt);
	void read_bitmap_foot(std::filesystem::path p, dynamic_bitset<>* bitmap, BarFileFoot* foot);
	void save_trading_date();
	inline void write_bitmap_foot(std::fstream& of,dynamic_bitset<>* bitmap,BarFileFoot* foot);
	void write_bars(std::fstream& of, std::map<uint32_t, std::vector<MinuteBar>>* bars, std::map<uint32_t, std::vector<MinuteBar>>::iterator start_it);
	inline void update_foot(std::map<uint32_t, Bar>* bars, dynamic_bitset<>* bitmap, BarFileFoot* foot);
	inline void update_foot(std::vector<Bar>* bars, dynamic_bitset<>* bitmap, BarFileFoot* foot);
	inline void update_foot(Bar*buf,int cnt,  dynamic_bitset<>* bitmap, BarFileFoot* foot);
	inline void update_foot(std::set<Bar> bars, dynamic_bitset<>* bitmap, BarFileFoot* foot);
	inline void update_foot(std::map<uint32_t, std::vector<MinuteBar>>* bars, dynamic_bitset<>* bitmap, BarFileFoot* foot);
	std::map<uint32_t, Bar> unpack_daybar(std::vector<char>* bytes);
public:
	~MyFileStore();
	MyFileStore(std::string dir);
	static MyFileStore *instance();
	void set_tdx_source(TdxFileStore* p) { tdx = p; };
	void start_import();

	//从tdx指数获取日期，合并到自己日期。
	//返回true:发生合并，false:未发生合并
	bool update_trading_date();
	bool update_daybar(Exchange e,  std::string symbol, Bar* b,int cnt);
	bool update_daybar(Exchange e,  std::string symbol, std::set<Bar> b);
	void read_daybar(std::filesystem::path f, std::map<uint32_t, Bar>* bars,dynamic_bitset<>* bitmap,BarFileFoot* foot);
	void read_daybar_all(std::filesystem::path f, std::set<Bar>* bars,dynamic_bitset<>* bitmap,BarFileFoot* foot);
	std::string_view get_daybar(Exchange exchange, std::string symbol, BarSize bs, int starttime, int endtime, int* rowsize=nullptr, int* rowcnt=nullptr);
	std::string_view get_rbar_series(Exchange exchange, std::string symbol, BarSize bs, int rindex, int rcount, int* rowsize=nullptr, int* rowcnt=nullptr);
	std::vector<Bar> get_daybar(Exchange exchange, std::string symbol);
	
	//根据日期序列，每天多少个bar，计算bit map和尾部信息，并合并为foot
	//std::vector<char> get_bitmap_and_foot(std::map<uint32_t, std::vector<MinuteBar>>* bars);
	//根据local分钟线byte，获取foot，bitmap和存储k线的map
	std::map<uint32_t, std::vector<MinuteBar>> unpack_minbar(std::vector<char>* bytes, dynamic_bitset<>* bitmap,BarFileFoot* foot);
	//将tdx的分钟bar文件合并到自己的文件
	bool update_minutebar(Exchange e, std::string symbol, std::map<uint32_t, std::vector<MinuteBar>>* bars);
	//读取全部min bar
	void read_minutebar(std::filesystem::path f, std::map<uint32_t, std::vector<MinuteBar>>* bars, dynamic_bitset<>* bitmap, BarFileFoot* foot) ;
	//指定目标分钟线，读取该分钟线的bit map序列和文件尾信息
	
	//读取指定标的、指定日期整天的1分钟bar
	std::vector<MinuteBar> select_fullday_minbar(Exchange e, std::string symbol, uint32_t date);


	// for debug use.
	void print_rows(std::map<uint32_t, Bar>* b);
	void print_rows(std::map<uint32_t, std::vector<MinuteBar>>* b);

	void print_bar_info(Exchange e,std::string symbol,BarSize bs);
	void print_foot(BarFileFoot* foot);
	void print_bitmap(dynamic_bitset<>* bitmap);



private:
	void change_format();
	void change_daybar_format();
	void move_from();
	void move_from_day();

};
inline void MyFileStore::write_bitmap_foot(std::fstream& of, dynamic_bitset<>* bitmap, BarFileFoot* foot)
{
	if(bitmap)
	of.write((char*)bitmap->data(),bitmap->total_bytes());
	if(foot)
		of.write((char*)foot, sizeof(BarFileFoot));

}
inline void MyFileStore::update_foot(std::map<uint32_t,Bar> * bars,dynamic_bitset<>* bitmap, BarFileFoot* foot)
{
	foot->firstdate = bars->begin()->first;
	foot->lastdate = bars->rbegin()->first;
	foot->rowsize = sizeof(Bar);
	foot->footsize = sizeof(BarFileFoot)+bitmap->total_bytes();
}
inline void MyFileStore::update_foot(std::vector<Bar>* bars, dynamic_bitset<>* bitmap, BarFileFoot* foot)
{
	foot->firstdate = bars->begin()->time;
	foot->lastdate = bars->rbegin()->time;
	foot->rowsize = sizeof(Bar);
	foot->footsize = sizeof(BarFileFoot) + bitmap->total_bytes();
}
inline void MyFileStore::update_foot(Bar*buf,int cnt, dynamic_bitset<>* bitmap, BarFileFoot* foot)
{	
	foot->firstdate = ((Bar*)(buf))->time;
	foot->lastdate = ((Bar*)(buf)+cnt)->time;
	foot->rowsize = sizeof(Bar);
	foot->footsize = sizeof(BarFileFoot) + bitmap->total_bytes();
}
inline void MyFileStore::update_foot(std::set<Bar> bars, dynamic_bitset<>* bitmap, BarFileFoot* foot)
{
	foot->firstdate = bars.begin()->time;
	foot->lastdate = bars.rbegin()->time;
	foot->rowsize = sizeof(Bar);
	foot->footsize = sizeof(BarFileFoot) + bitmap->total_bytes();
}
inline void MyFileStore::update_foot(std::map<uint32_t, std::vector<MinuteBar>>* bars, dynamic_bitset<>* bitmap, BarFileFoot* foot)
{
	foot->firstdate = bars->begin()->first;
	foot->lastdate = bars->rbegin()->first;
	foot->rowsize = 4+ sizeof(MinuteBar)* bars->begin()->second.size();
	foot->footsize = sizeof(BarFileFoot) + bitmap->total_bytes();
}
